package com.example.armmvvm.ui.customdraw.view

import android.animation.AnimatorSet
import android.animation.ObjectAnimator
import android.content.Context
import android.graphics.Canvas
import android.graphics.Paint
import android.util.AttributeSet
import androidx.appcompat.widget.AppCompatEditText
import com.example.arm.ext.dp
import com.example.armmvvm.R
import timber.log.Timber
import kotlin.math.abs

/**
 * @author 创建人 ：yanghaozhang
 * @version 1.0
 * @package 包名 ：com.example.armmvvm.ui.customdraw.view
 * @createTime 创建时间 ：2022/2/25
 * @modifyBy 修改人 ：
 * @modifyTime 修改时间 ：
 * @modifyMemo 修改备注：
 */
class MaterialEditText @JvmOverloads constructor(
    context: Context, attrs: AttributeSet? = null, defStyleAttr: Int = R.attr.editTextStyle
) : AppCompatEditText(context, attrs, defStyleAttr) {

    private val paintDesign = Paint(Paint.ANTI_ALIAS_FLAG).apply {
        alpha = 0
    }

    private var tipsChangeAnimatorSet: AnimatorSet? = null


    /**
     * 为了减少自身的计算,分为了两个动画,而实际上可以一个0f~1f的动画即可
     * 如果动画执行快,且只有一个动画的情况下,可以仅创建一个动画的成员变量,如floatTipsAnimator
     * 通过调用start()/reverse()进行
     * 百分比
     */
    private var floatTipsPercent = 1f
        set(value) {
            field = value
            invalidate()
        }
    private val floatTipsAnimator = ObjectAnimator.ofFloat(this, "floatTipsPercent", 0f, 1f).apply {
        duration = 300
    }

    private val textDesignSize = 12.dp
    private val textDesignPadding = 16.dp
    private val horizontalOffset = 5.dp
    private val minYOffset = 15.dp
    private val maxYOffset = minYOffset + textDesignSize + textDesignPadding

    private var isShowing = false

    private var curYOffset = maxYOffset
        set(value) {
            field = value
            invalidate()
        }

    private var alphaDesign = 0
        set(value) {
            field = value
            paintDesign.alpha = value
        }

    private var useFloatLabel = false
        set(value) {
            if (field != value) {
                field = value
                if (field) {
                    setPadding(paddingLeft, (paddingTop + textDesignSize + textDesignPadding).toInt(), paddingRight, paddingBottom)
                } else {
                    setPadding(paddingLeft, (paddingTop - textDesignSize - textDesignPadding).toInt(), paddingRight, paddingBottom)
                }
            }
        }

    init {
        paintDesign.textSize = textDesignSize
//        val typedArray = context.obtainStyledAttributes(attrs, R.styleable.MaterialEditText)
//        useFloatLabel = typedArray.getBoolean(R.styleable.MaterialEditText_useFloatLabel, true)
        // 通过R文件的读取,可以明白解析的原理
        // R.styleable.MaterialEditText::实际是一个包含对应的属性的数组
        // R.styleable.MaterialEditText_useFloatLabel::实际上是一个序号,在R.styleable.MaterialEditText数组里的角标
        val typedArray = context.obtainStyledAttributes(attrs, intArrayOf(R.attr.useFloatLabel))
        useFloatLabel = typedArray.getBoolean(0, true)
        typedArray.recycle()
    }

    override fun onTextChanged(text: CharSequence?, start: Int, lengthBefore: Int, lengthAfter: Int) {
        if (!useFloatLabel) {
            return
        }
        super.onTextChanged(text, start, lengthBefore, lengthAfter)
        val targetYOffset = getTargetYOffset(text)
        if (curYOffset.compareTo(0f) == 0) {
            return
        }
        if ((getShouldShow(text) && !isShowing) || (!getShouldShow(text) && isShowing)) {
            isShowing = !isShowing
            Timber.d("--->ShouldShow::$isShowing")
            // 当动画执行时间长的时候,必须要取消上一个属性动画
            tipsChangeAnimatorSet?.cancel()
            val targetAlpha = getTargetAlpha(text)
            // ObjectAnimator::
            // 如果给定的值只有一个时,该值为终点值
            //      1,通过propertyName的get方法获取第一个值
            //      2,如果拿不到,则起始值取0
            // 如果这里的curYOffset是private,是会取不到值的,要么去掉private,要么主动给起始值
            val yOffsetAnimation = ObjectAnimator.ofFloat(this, "curYOffset", curYOffset, targetYOffset)
            val alphaAnimation = ObjectAnimator.ofInt(this, "alphaDesign", alphaDesign, targetAlpha)
            val time = abs(targetYOffset - curYOffset) * 1000 / (maxYOffset - minYOffset)

            tipsChangeAnimatorSet = AnimatorSet().apply {
                playTogether(yOffsetAnimation, alphaAnimation)
                duration = time.toLong()
                start()
            }
        }
    }

    private fun getShouldShow(text: CharSequence?) = !text.isNullOrEmpty()

    private fun getTargetYOffset(text: CharSequence?) = if (text.isNullOrEmpty()) {
        maxYOffset
    } else {
        minYOffset
    }

    private fun getTargetAlpha(text: CharSequence?) = if (text.isNullOrEmpty()) {
        0
    } else {
        255
    }

    override fun onDraw(canvas: Canvas) {
        super.onDraw(canvas)
        if (curYOffset.compareTo(getTargetYOffset(text)) != 0) {
            Timber.d(curYOffset.toString())
        }
        if (useFloatLabel) {
            canvas.drawText(hint.toString(), horizontalOffset, curYOffset, paintDesign)
        }
    }

}